using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace Sedodream.Sudoku.Board
{
	[DebuggerDisplay("{Location}:{CellValue}")]
	public class Cell : ICell
	{
		#region Fields
		private IBoard board;
		//private int? cellValue;
		private IPoint location;
		private int? cellComplexity;
		private IList<int> allowedNumbers;
		#endregion

		#region Constructors
		public Cell(IBoard boardData, IPoint location)
		{
			this.board = boardData;
			this.location = location;
			this.cellComplexity = null;

			//boardData.BoardData.BoardChanged +=new Sedodream.Sudoku.Events.BoardDataChanged(boardData_BoardChanged);
		}

		public Cell(IBoard boardData, IPoint location, int? cellComplexity)
			: this(boardData, location)
		{
			this.cellComplexity = cellComplexity;
		}
		#endregion

		#region ICell implementation
		public int? CellComplexity
		{
			get { return cellComplexity; }
			set { cellComplexity = value; }
		}
		public IPoint Location
		{
			get { return location; }
		}
		public int? CellValue
		{
			get 
			{
				return Board.BoardData[this.Location.Row, this.Location.Col];
				//return cellValue; 
			}
			set 
			{
				this.Board.SetValueAt(this.Location, value);
				//cellValue = value; 
			}
		}
		public IBoard Board
		{
			get { return board; }
		}
		public IList<int> AllowedNumbers
		{
			get
			{
				if (allowedNumbers == null)
					allowedNumbers = new List<int>();
				return allowedNumbers;
			}
		}
		#endregion

		public override string ToString()
		{
			return string.Format("[{0}:{1}]", Location, CellValue);
		}
		public void Update()
		{
			//return;
			//the allowed numbers might need to be changed
			if (this.CellValue.HasValue)
			{
				if (AllowedNumbers.Count > 0)
				{
					this.AllowedNumbers.Clear();
					this.CellComplexity = int.MinValue;
				}
				return;
			}

			//repopulate the AllowedNumbers
			AllowedNumbers.Clear();
			for (int i = 1; i < this.Board.BoardData.SideLength+1; i++)
			{
				AllowedNumbers.Add(i);
			}

			IList<ICellGroup> groups = this.Board.FindAllGroupsContaining(this.Location);
			foreach (ICellGroup group in groups)
			{
				if (group == null)
					continue;

				foreach (ICell cell in group.Cells)
				{
					if (cell.CellValue != null && AllowedNumbers.Contains(cell.CellValue.Value))
					{
						AllowedNumbers.Remove(cell.CellValue.Value);
					}

				}
				//--The above is slightly faster than the below code
				//foreach (int value in group.Values)
				//{
				//    if (AllowedNumbers.Contains(value))
				//    {
				//        AllowedNumbers.Remove(value);
				//    }
				//}
			}
			if (AllowedNumbers.Count <= 0)
			{
				this.cellComplexity = int.MaxValue;
				board.State = BoardState.Failed;
			}
			this.cellComplexity = AllowedNumbers.Count;
			
		}
		void boardData_BoardChanged(object sender, Sedodream.Sudoku.Events.BoardChangedEventArgs args)
		{
			Update();
		}
	}
}
